/*
 *  $Id: AffectIcon.cs 1083 2010-05-24 10:28:38Z thenn.erannor $
 *    This file is a part of Ragima CCG.
 *    (C) 2008-2009 Ragima development group.
 *
 *    Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System.Collections.Generic;

using AgateLib.Geometry;
using AgateLib.InputLib;

namespace Ragima {
    /// <summary>
    /// Индексы иконок эффектов. Расчитываются как index=y*32+x, где x и y - положение на общем изображении иконок
    /// </summary>
    public enum AffectIcon: int {
        None = -1,
        Resurrect = 0,
        Parasite = 1,
        Venom = 2,
        Wound = 3,
        Poison = 4,
        Scorch = 5,
        Sinner = 6,
        Flight = 7,
		Aquatic = 8,
        NonBlocked = 9,
        Agility = 10,
        Hero = 11,
        Tireless = 12,
        Idler = 13,
        Sleeper = 14,
        AlwaysBlocked = 15,
        Antimagic = 16,
        Berserk = 17,
        Brutal = 18,
        Deluge = 19,
        DisableAttack = 20,
        Fearless = 21,
        FirstStrike = 22,
        Immortal = 23,
        Inerrancy = 24,
        Lifeless = 25,
        MassBlock = 26,
        Slow = 27,
        Sorrow = 28,
        SorrowIgnore = 29,
        Unbind = 30,
        Vanguard = 31,
        Undead = 32,
        ImmuneScorch = 33,
        Spirit = 34,
        FlightBlock = 35,
        Guardian = 36,
        Attacker = 37,
        Holy = 38,
        Vampire = 39,
        Regeneration = 40,
        Scavenger = 41,
        Cannibal = 42,
        ParasiteAttack = 43,
        MagicAttack = 44,
        WoundAttack = 45,
        VenomAttack = 46,
        Death = 47,
        CriticalStrike = 48,
        DeathStare = 49,
        Eating = 50,
        Fast = 51,
        Fear = 52,
        FearAura = 53,
        FinishKill = 54,
        MultiBlock = 55,
        Paralysis = 56,
        Reincarnation = 57,
        Rogue = 58,
        SwornEnemy = 59,
        Undying = 60,
        ImmuneWound = 61,

        PhaseIcons = 1019,
        Player1OffencePhase = PhaseIcons+3,
        Player1DefencePhase = PhaseIcons+4,
        Player2OffencePhase = PhaseIcons+1,
        Player2DefencePhase = PhaseIcons+2,
        BattlePhase = PhaseIcons+0,
    }

    /// <summary>
    /// Словарь для эффектов, распределенных по индексам иконок.
    /// </summary>
    public sealed class AffectIconDictionary {
        private Dictionary<AffectIcon, List<Affect>> _affects;
        private int _version;

        public AffectIconDictionary() {
            _affects = new Dictionary<AffectIcon, List<Affect>>();
            _version = 0;
        }

        public int Version {
            get { return _version; }
        }

        public void Clear() {
            _affects.Clear();
            _version++;
        }

        public void Add(Affect affect) {
            if (!affect.HasIcon) return;
            List<Affect> list;
            if (_affects.ContainsKey(affect.Icon))
                list = _affects[affect.Icon];
            else {
                list = new List<Affect>();
                _affects.Add(affect.Icon, list);
            }
            list.Add(affect);
            _version++;
        }

        public void Remove(Affect affect) {
            if (!affect.HasIcon) return;
            if (!_affects.ContainsKey(affect.Icon)) return;
            List<Affect> list = _affects[affect.Icon];
            list.Remove(affect);
            if (list.Count == 0)
                _affects.Remove(affect.Icon);
            _version++;
        }

        private static bool HasIcon(List<Affect> affects) {
            if (affects.Count == 0) return false;
            Affect affect = affects[0];
            if (affect is FlagAffect && affect.Owner != null && !affect.LocalSummary.Flags.HasFlag(affect.GetType())) return false;
            return true;
        }

        public IEnumerable<AffectIcon> GetIcons() {
            foreach (KeyValuePair<AffectIcon, List<Affect>> icon in _affects)
                if (HasIcon(icon.Value))
                    yield return icon.Key;
        }

        public IEnumerable<AffectIconItem> GetItems(Point start, int inLine) {
            Size size = AffectIconItem.IconSprite.Descriptor.Size;
            Point pos = start;
            int i = 0;
            foreach (KeyValuePair<AffectIcon, List<Affect>> icon in _affects) {
                if (HasIcon(icon.Value)) {
                    yield return new AffectIconItem(new Rectangle(pos, size), icon.Value);
                    pos.X += size.Width;
                    i++;
                    if (i >= inLine) {
                        pos.X = start.X;
                        i = 0;
                        pos.Y += size.Height;
                    }
                }
            }
        }
    }

    public class AffectIconItem {
        private static UI.Sprite _icons;
        public static UI.Sprite IconSprite {
            get { return _icons ?? (_icons = Data.StatusIcons.GetSprite("icons")); }
        }

        public readonly Rectangle Rect;
        public readonly List<Affect> Affects;

        public AffectIconItem(Rectangle rect, List<Affect> affects) {
            Rect = rect;
            Affects = affects;
        }

        public AffectIcon Icon {
            get {
                if (Affects == null || Affects.Count == 0) return AffectIcon.None;
                return Affects[0].Icon;
            }
        }

        public void Draw() {
            IconSprite.Draw((int) Icon, Rect.Location);
        }

        public string GetHintText() {
            if (Affects.Count == 0) return string.Empty;
            string iconDesc = Affects[0].IconDescriptionText;
            bool hasDesc = Application.Config.Interface.DetailAffectDescription && !string.IsNullOrEmpty(iconDesc);
            int count = Affects.Count;
            if (hasDesc) count++;
            string[] text = new string[count];
            for (int i = 0; i < Affects.Count; i++)
                text[i] = Affects[i].NameText;
            if (hasDesc)
                text[count-1] = iconDesc;
            return string.Join("\n", text);
        }
    }

    public class AffectIconItems {
        private int _inLine;
        private AffectIconDictionary _icons;
        private int _version;
        private Point _start;
        private List<AffectIconItem> _items;

        public AffectIconItems(int inLine) {
            _inLine = inLine;
            _icons = null;
            _version = 0;
            _items = new List<AffectIconItem>();
        }

        public int Count {
            get { return _items.Count; }
        }

        public AffectIconItem this[int i] {
            get { return _items[i]; }
        }

        public void Update(AffectIconDictionary newIcons, Point start) {
            if (_icons == newIcons && _icons.Version == _version && _start.Equals(start))
                return;
            _icons = newIcons;
            _version = _icons.Version;
            _start = start;
            _start.X += 2;
            _start.Y += 2;
            _items.Clear();
            _items.AddRange(_icons.GetItems(_start, _inLine));
        }

        public void Draw() {
            if (_items.Count == 0) return;
            foreach (AffectIconItem item in _items) item.Draw();
        }

        public AffectIconItem Find(Point point) {
            foreach (AffectIconItem item in _items)
                if (item.Rect.Contains(point))
                    return item;
            return null;
        }

        public AffectIconItem FindByMouse() {
            return Find(Mouse.Position);
        }
    }

    public class AffectIconHint {
        private AffectIconItem _item;
        private Hint _hint;

        public AffectIconHint() {
            _item = null;
            _hint = null;
        }

        public Hint GetHint(AffectIconItem item) {
            if (item == _item) return _hint;
            _item = item;
            _hint = (_item != null) ? new TextHint(_item.Rect, _item.GetHintText()) : null;
            return _hint;
        }
    }
}
